﻿using System;
using System.Data;
using System.Web;
using System.Web.UI.WebControls;
using System.Data.Common;

namespace SqlPaging
{    
    /// <summary>
    /// Used by SqlPagingDataSource to hand off the paging to the database server.
    /// </summary>
    public class SqlPagingDataSourceView : SqlDataSourceView
    {
        private bool _enablePaging;
        private string _maximumRowsParameterName;
        private string _startRowIndexParameterName;
        private string _countParameterName;
        private SqlPagingDataSource _owner;

        public SqlPagingDataSourceView(SqlPagingDataSource owner, string name, HttpContext context)
            : base(owner, name, context)
        {
            _owner = owner;
        }

        public bool EnablePaging
        {
            get { return _enablePaging; }
            set
            {
                if (_enablePaging != value)
                {
                    _enablePaging = value;
                    this.OnDataSourceViewChanged(EventArgs.Empty);
                }
            }
        }
      
        public override bool CanPage
        {
            get
            {
                return _enablePaging;
            }
        }

        /// <summary>
        /// Used by paging controls. Some paging controls will only work if this is true.
        /// <value>Returns true if EnablePaging is true and the CountOnlyParameter is not empty.</value>
        /// </summary>
        public override bool CanRetrieveTotalRowCount
        {
            get
            {
                return _enablePaging && !string.IsNullOrEmpty(this.CountParameterName);                
            }
        }

        #region Paging Parameters

        public string MaximumRowsParameterName
        {
            get
            {
                if (this._maximumRowsParameterName == null)
                {
                    return "maximumRows";
                }
                return this._maximumRowsParameterName;
            }
            set
            {
                if (this.MaximumRowsParameterName != value)
                {
                    this._maximumRowsParameterName = value;
                    this.OnDataSourceViewChanged(EventArgs.Empty);
                }
            }
        }

        public string StartRowIndexParameterName
        {
            get
            {
                if (this._startRowIndexParameterName == null)
                {
                    return "startRowIndex";
                }
                return this._startRowIndexParameterName;
            }
            set
            {
                if (this.StartRowIndexParameterName != value)
                {
                    this._startRowIndexParameterName = value;
                    this.OnDataSourceViewChanged(EventArgs.Empty);
                }
            }
        }

        /// <summary>
        /// The name of the parameter that when passed to the database will 
        /// return only the total count of records instead of the actual results.
        /// </summary>
        public string CountParameterName
        {
            get
            {
                if (this._countParameterName == null)
                {
                    return "countOnly";
                }
                return this._countParameterName;
            }
            set
            {
                if (this._countParameterName != value)
                {
                    this._countParameterName = value;
                    this.OnDataSourceViewChanged(EventArgs.Empty);
                }
            }
        }

        #endregion //Paging Parameters

        protected override void OnSelecting(SqlDataSourceSelectingEventArgs e)
        {            
            DbCommand cmd = e.Command;
            DbConnection connection = cmd.Connection;

            if (e.Arguments.RetrieveTotalRowCount)
            {
                string countOnlyParameterName = this.CountParameterName;                
                if (!cmd.Parameters.Contains(countOnlyParameterName))
                    cmd.Parameters.Add(this._owner.CreateParameter(this.ParameterPrefix + countOnlyParameterName, true));                
                try
                {
                    if (connection.State != ConnectionState.Open)
                    {
                        connection.Open();
                    }
                    //Retrieve count
                    e.Arguments.TotalRowCount = (int)cmd.ExecuteScalar();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (connection.State == ConnectionState.Open)
                    {
                        connection.Close();
                    }
                }                                
                //Reset count only to false for actual select query
                cmd.Parameters[this.ParameterPrefix + countOnlyParameterName].Value = false;
            }

            if (this.EnablePaging)
            {
                string maximumRowsParameterName = this.MaximumRowsParameterName;
                string startRowIndexParameterName = this.StartRowIndexParameterName;
                if (string.IsNullOrEmpty(maximumRowsParameterName) || string.IsNullOrEmpty(startRowIndexParameterName))
                {
                    throw new InvalidOperationException("Missing Paging Parameters");
                }
                if (!cmd.Parameters.Contains(startRowIndexParameterName))
                    cmd.Parameters.Add(this._owner.CreateParameter(this.ParameterPrefix + startRowIndexParameterName, e.Arguments.StartRowIndex));

                if (!cmd.Parameters.Contains(maximumRowsParameterName))
                    cmd.Parameters.Add(this._owner.CreateParameter(this.ParameterPrefix + maximumRowsParameterName, e.Arguments.MaximumRows));
            }

            base.OnSelecting(e);
        }
    }
}